package com.fubowen.reader.adapter

import android.graphics.Rect
import android.view.ViewGroup.MarginLayoutParams
import androidx.core.view.updateLayoutParams
import androidx.recyclerview.widget.RecyclerView
import com.fubowen.reader.extension.getItemView
import kotlin.math.max

class AutoGridLayoutManager(val grid: Int = 0, val hGap: Int = 0, val vGap: Int = 0) : RecyclerView.LayoutManager() {

    private val maxW: Int get() = (width - paddingLeft - paddingRight)
    private val maxH: Int get() = (height - paddingTop - paddingBottom)
    override fun generateDefaultLayoutParams() = RecyclerView.LayoutParams(
        RecyclerView.LayoutParams.WRAP_CONTENT,
        RecyclerView.LayoutParams.WRAP_CONTENT
    )

    override fun isAutoMeasureEnabled() = true

    override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
        if (childCount == 0 && state.isPreLayout) {
            return
        }
        detachAndScrapAttachedViews(recycler)
        val hGridList = splitGrid(maxW, grid, vGap, paddingLeft)
        layoutChildren(recycler, hGridList, paddingTop, 0)
    }

    private fun layoutChildren(recycler: RecyclerView.Recycler, hGridList: List<Grid>, top: Int, position: Int) {
        var usedWidth = 0
        var maxLineHeight = 0
        for (i in position until itemCount) {
            val itemView = getItemView(recycler, i)
            val start = hGridList.find { it.start >= usedWidth }
            if (start == null) {
                layoutChildren(recycler, hGridList, top + maxLineHeight + hGap, i)
                break
            }
            val end = hGridList.find { it.end >= (start.start + itemView.width) }
            if (end == null) {
                layoutChildren(recycler, hGridList, top + maxLineHeight + hGap, i)
                break
            }
            usedWidth = end.end
            maxLineHeight = max(maxLineHeight, itemView.height)
            val rect = Rect(start.start, top, end.end, top + itemView.height)
            layoutDecorated(itemView.view, start.start, top, end.end, top + itemView.height)
            itemView.view.updateLayoutParams<MarginLayoutParams> {
                width = rect.width()
                itemView.view.requestLayout()
            }
        }
    }

    private fun splitGrid(hw: Int, grid: Int, gap: Int, offset: Int): List<Grid> {
        val num = (hw + gap) / (grid + gap)
        val freeSpace = hw - (num * grid + num * gap - gap)
        val extra = freeSpace / num
        val newGrid = grid + extra
        return (0..hw).chunked(newGrid + gap).map { Grid(it.first() + offset, it.last() + offset - gap) }.apply {
            last().end += gap
        }
    }

    data class Grid(var start: Int, var end: Int)
}